package gao.xaiolei.service;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import javax.annotation.Resource;
import gao.xaiolei.dao.*;
import gao.xaiolei.dto.*;
import gao.xaiolei.enity.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import xiaolei.gao.Image.ImageInterface;
import xiaolei.gao.file.FileInterface;
import gao.xaiolei.util.ServiceName;
import gao.xaiolei.util.UuidUtil;

@Service("TaskService")
public class TaskService {

    @Autowired
    private RestTemplate restTemplate;

    @Resource(name = "ITaskDao")
    private ITaskDao iTaskDao;

    @Resource(name = "ITaskReceiverDao")
    private ITaskReceiverDao iTaskReceiverDao;

    @Resource(name = "ITaskAttachedDao")
    private ITaskAttachedDao iTaskAttachedDao;

    @Resource(name = "ITaskTypeDao")
    private ITaskTypeDao iTaskTypeDao;

    @Resource(name = "ITaskStatusDao")
    private ITaskStatusDao iTaskStatusDao;

    @Resource(name = "ITaskPriority")
    private ITaskPriority iTaskPriority;

    @Resource(name = "ITaskViewDao")
    private ITaskViewDao iTaskViewDao;

    @Resource(name = "ITaskReceiverViewDao")
    private ITaskReceiverViewDao iTaskReceiverViewDao;

    @Resource(name = "ITaskGroupDao")
    private ITaskGroupDao iTaskGroupDao;

    @Resource(name = "FileInterface")
    private FileInterface fileInterface;

    @Resource(name = "ImageInterface")
    private ImageInterface imageInterface;

    @Transactional
    public void addTask(TaskInDto taskInDto) {
        Task task = taskInDto.getTask();
        List<TaskAttached> attacheds = taskInDto.getAttacheds();
        iTaskAttachedDao.saveAll(attacheds);//保存任务附件信息
        task.setIsAttachment(attacheds.size() == 0 ? 0 : 1);// 判断是否有附件
        task.setCreateDate(LocalDateTime.now());// 新建的话就自己生成时间
        iTaskDao.save(task);
        // 然后在重新添加收件人记录
        List<String> receivers = taskInDto.getReceivers();
        if (task.getIsGroup() == 1) {// 判断传进来的接收者Id是用户Id还是组Id
            // 如果是组Id则要将该组的组长查出来逐一保存到接收者表中并且把组id保存到任务-组关系表
            for (int i = 0, length = receivers.size(); i < length; i++) {
                iTaskGroupDao.save(new TaskGroup(task.getId(), receivers.get(i)));
                String leader = restTemplate.getForObject(
                        ServiceName.AUTH_SERVICE.getServiceName().concat("/user/groupLeader/").concat(receivers.get(i)), String.class);
                iTaskReceiverDao.save(new TaskReceiver(task.getId(), leader, task.getStatus()));
            }
        } else {// 如果不是组Id则直接将此接收者绑定该任务然后保存到数据库
            for (int i = 0, length = receivers.size(); i < length; i++) {
                iTaskReceiverDao.save(new TaskReceiver(task.getId(), receivers.get(i), task.getStatus()));
            }
        }
    }

    @Transactional
    public void updateTask(TaskInDto taskInDto) {
        Task task = taskInDto.getTask();
        Task oldTask = iTaskDao.queryByTaskId(task.getId());
        List<TaskAttached> newAttacheds = taskInDto.getAttacheds();
        List<TaskAttached> oldAttacheds = iTaskAttachedDao.findByTaskId(task.getId());
        List<String> receivers = taskInDto.getReceivers();
        task.setIsAttachment(newAttacheds.size() == 0 ? 0 : 1);
        if (oldTask.getIsGroup() == 0)//先将原来的收件人和收件组删掉
            iTaskGroupDao.deleteAllByTaskId(task.getId());
        iTaskReceiverDao.deleteByTaskId(task.getId());
        //然后再将新的收件人或收件组保存
        if (task.getIsGroup() == 1) {// 判断传进来的接收者Id是用户Id还是组Id
            // 如果是组Id则要将该组的组长查出来逐一保存到接收者表中并且把组id保存到任务-组关系表
            for (int i = 0, length = receivers.size(); i < length; i++) {
                iTaskGroupDao.save(new TaskGroup(task.getId(), receivers.get(i)));
                String leader = restTemplate.getForObject(
                        ServiceName.AUTH_SERVICE.getServiceName().concat("/user/groupLeader/").concat(receivers.get(i)), String.class);
                iTaskReceiverDao.save(new TaskReceiver(task.getId(), leader, task.getStatus()));
            }
        } else {// 如果不是组Id则直接将此接收者绑定该任务然后保存到数据库
            for (int i = 0, length = receivers.size(); i < length; i++) {
                iTaskReceiverDao.save(new TaskReceiver(task.getId(), receivers.get(i), task.getStatus()));
            }
        }
        Map<String, Integer> willDeleteFile = new HashMap<>();
        for (int i = 0, length = oldAttacheds.size(); i < length; i++) {//查看旧附件里面是否有要删除的
            boolean isDelete = true;
            for (int j = 0, length2 = newAttacheds.size(); j < length2; j++) {
                if (oldAttacheds.get(i).getId().equals(newAttacheds.get(j).getId())) {
                    isDelete = false;
                    break;
                }
            }
            if (isDelete) {
                willDeleteFile.put(oldAttacheds.get(i).getUuid(), oldAttacheds.get(i).getFileType());
                iTaskAttachedDao.deleteById(oldAttacheds.get(i).getId());
            }
        }
        for (int i = 0, length = newAttacheds.size(); i < length; i++) {//查看新附件面是否有本来就存在的附件
            boolean isDelete = false;
            for (int j = 0, length2 = oldAttacheds.size(); j < length2; j++) {
                if (oldAttacheds.get(j).getId().equals(newAttacheds.get(i).getId())) {
                    isDelete = true;
                    break;
                }
            }
            if (isDelete) {//如果有的话就不用保存了
                newAttacheds.remove(i);
                i--;
                length--;
            }
        }
        iTaskAttachedDao.saveAll(newAttacheds);
        task.setCreateDate(oldTask.getCreateDate());
        iTaskDao.save(task);//保存任务本身
        for (Map.Entry<String, Integer> wd : willDeleteFile.entrySet()) {//最后才调用文件服务去删除附件
            if (wd.getValue() == 0)
                imageInterface.imageDelete(wd.getKey());
            else
                fileInterface.fileDelete(wd.getKey());
        }
    }

    // 收件人修改任务为已完成
    @Transactional
    public void updateTaskStatusForReceiver(List<String> taskIds, String receiverId) {
        for (int i = 0, length = taskIds.size(); i < length; i++) {
            iTaskReceiverDao.updateStatus(receiverId, taskIds.get(i), 3);
            TaskReceiver receiverExample = new TaskReceiver();
            receiverExample.setId(new TaskReceiverId(taskIds.get(i), null));
            List<TaskReceiver> allReceiver = iTaskReceiverDao.findAll(Example.of(receiverExample));
            int j = 0, length2;
            for (j = 0, length2 = allReceiver.size(); j < length2; j++) {
                if (allReceiver.get(j).getStatus() < 3)
                    break;
            }
            if (j == allReceiver.size())//如果该任务的其他收件人也完成了这个任务，就要把这个任务从未读改为已完成
                iTaskDao.updateStatus(3, taskIds.get(i));
        }
    }

    // 发件人修改任务为已取消
    @Transactional
    public void updateTaskStatusForResponsible(List<String> taskIds) {
        for (int i = 0, length = taskIds.size(); i < length; i++) {
            iTaskDao.updateStatus(-1, taskIds.get(i));
            TaskReceiver receiverExample = new TaskReceiver();
            receiverExample.setId(new TaskReceiverId(taskIds.get(i), null));
            List<TaskReceiver> allReceiver = iTaskReceiverDao.findAll(Example.of(receiverExample));
            for (int j = 0, length2 = allReceiver.size(); j < length2; j++) {//同时还要将收件人和任务关系的状态也修改为已取消
                allReceiver.get(j).setStatus(-1);
                iTaskReceiverDao.save(allReceiver.get(j));
            }
        }
    }

    // 获取该用户收到的所有任务的列表
    @Transactional(readOnly = true)
    public TaskReceiverListDto getTaskListByReceiverId(String receiverId, Integer status, int page, int size) {
        Page<TaskReceiverView> result = null;
        page = page == 0 ? 0 : page - 1;
        if (status == -2) {
            result = iTaskReceiverViewDao.findAllByReceiverAndStatusNumAfterOrderByCreateDateDesc(receiverId, 0, PageRequest.of(page, size, Sort.by(Sort.Order.desc("createDate"))));
        } else {
            TaskReceiverView viewExample = new TaskReceiverView();
            viewExample.setId(new TaskReceiverId(null, receiverId));
            viewExample.setStatusNum(status);
            result = iTaskReceiverViewDao.findAll(Example.of(viewExample), PageRequest.of(page, size, Sort.by(Sort.Order.desc("createDate"))));
        }
        return new TaskReceiverListDto(result.getContent(), iTaskReceiverDao.getCountReceiverNoread(receiverId, 1), result.getTotalElements());//查出该用户未读任务数量
    }

    // 获取该用户发送的所有任务的列表
    @Transactional(readOnly = true)
    public TaskResponseListDto getTaskListByResponsible(String responsible, Integer status, int page, int size) {
        TaskView viewExample = new TaskView();
        page = page == 0 ? 0 : page - 1;
        viewExample.setResponsible(responsible);
        viewExample.setStatusName(status == -2 ? null : iTaskStatusDao.getName(status));//如果是-2代表没有筛选条件
        Page<TaskView> result = iTaskViewDao.findAll(Example.of(viewExample), PageRequest.of(page, size, Sort.by(Sort.Order.desc("createDate"))));
        return new TaskResponseListDto(result.getContent(), result.getTotalElements());
    }

    // 针对接收者根据任务Id来获取任务详细信息的json字符串(包含任务、链接、附件信息)
    @Transactional
    public TaskOutDto getTaskByIdForReceiver(String id, String currentUserId) {
        TaskView tv = iTaskViewDao.queryByTaskId(id);
        String name = restTemplate.getForObject(ServiceName.AUTH_SERVICE.getServiceName().concat("/user/realName/").concat(tv.getResponsible()), String.class);
        TaskView tvOut = new TaskView();
        BeanUtils.copyProperties(tv, tvOut);//不能直接在查询出来的实体类赋值，不然就会把数据库里的值也更改掉
        tvOut.setResponsible(name);
        List<TaskAttached> av = iTaskAttachedDao.findByTaskId(id);
        TaskReceiver receiver = iTaskReceiverDao.findById(new TaskReceiverId(id, currentUserId)).orElseThrow(() -> new IllegalArgumentException("当前用户("
                .concat(currentUserId)
                .concat(")没有收到任务(")
                .concat(id)));
        if (receiver.getStatus() == 1) {//如果查看了就要把任务对收件人的关系状态改为已读
            receiver.setStatus(2);
            iTaskReceiverDao.save(receiver);
            List<Integer> allReceiverStatus = iTaskReceiverDao.getTaskAllReceiveStatus(id);
            int i = 0, length;
            for (i = 0, length = allReceiverStatus.size(); i < length; i++) {
                if (allReceiverStatus.get(i) <= 1)
                    break;
            }
            if (i == allReceiverStatus.size())//如果该任务的其他收件人也阅读了这个任务，就要把这个任务从未读改为已读
                iTaskDao.updateStatus(2, id);
        }
        tvOut.setStatusName(iTaskStatusDao.getName(receiver.getStatus()));//将输出的状态改为接收者的状态
        return new TaskOutDto(tvOut, null, av);
    }

    // 针对发送者根据任务Id来获取任务详细信息的json字符串(包含任务、链接、附件信以及收件人信息)
    @Transactional(readOnly = true)
    public TaskOutDto getTaskByIdForResponsible(String id) {
        TaskView tv = iTaskViewDao.queryByTaskId(id);
        int isGroup = tv.getIsGroup();
        List<ReceiverDto> receiverDtos = new ArrayList<>();
        if (isGroup == 0) {// 如果接收人不是组的话
            List<String> receivers = iTaskReceiverDao.queryByTaskId(id);// 获取任务的收件人列表
            for (int i = 0, length = receivers.size(); i < length; i++) {
                String name = restTemplate.getForObject(ServiceName.AUTH_SERVICE.getServiceName().concat("/user/realName/")
                        .concat(receivers.get(i)), String.class);
                receiverDtos.add(new ReceiverDto(receivers.get(i), name));
            }
        } else {// 如果是组的话则去获取组的名字
            List<String> groupIds = iTaskGroupDao.queryGroupByTaskId(id);// 获取任务的收件组列表
            for (int i = 0, length = groupIds.size(); i < length; i++) {
                String name = restTemplate.getForObject(ServiceName.AUTH_SERVICE.getServiceName().concat("/user/groupName/")
                        .concat(groupIds.get(i)), String.class);
                receiverDtos.add(new ReceiverDto(groupIds.get(i), name));
            }
        }
        List<TaskAttached> attacheds = iTaskAttachedDao.findByTaskId(id);
        return new TaskOutDto(tv, null, attacheds, receiverDtos);
    }

    // // 调用文件服务上传附件
    // @Transactional
    // public String uploadAttached(RestTemplate restTemplate, MultipartFile
    // file,
    // int fileType) throws IllegalStateException, IOException {
    // // 判断传输过来的文件是什么类型,从而决定要请求哪个文件服务来保存
    // if (fileType == 0) {// 如果是图片文件则调用Training-ImageManage-Service
    // return new ImageInterface(restTemplate).imageUpload(file);
    // } else {// 如果是普通文件则调用Training-FileManage-Service
    // String uuid = UUID.randomUUID().toString().replaceAll("-", "");
    // if ("保存成功".equals(new FileInterface(restTemplate).fileUpload(file,
    // uuid))) {
    // return uuid;
    // } else
    // throw new RuntimeException("文件上传失败！");
    // }
    // }

    // 调用文件服务上传附件
    public String uploadAttached(int fileType, MultipartFile file)
            throws IOException {
        // 判断传输过来的文件是什么类型,从而决定要请求哪个文件服务来保存
        if (fileType == 0) {// 如果是图片文件则调用Training-ImageManage-Service
            return imageInterface.imageUpload(file);
        } else {// 如果是普通文件则调用Training-FileManage-Service
            String uuid = UuidUtil.get32Uuid();
            fileInterface.fileUpload(file, uuid);
            return uuid;
        }
    }

    // 先去数据库删除该附件的记录,然后调用文件服务删除附件
    @Transactional
    public void deleteAttached(String hashOrUuid, int fileType,
                               String attachedId) {
        String taskId = iTaskAttachedDao.getTaskIdOf(attachedId);
        if (iTaskAttachedDao.getCountByTaskId(taskId) <= 1)// 如果该任务本来就只剩1个附件的话就要先把任务的附件标志位置为0
            iTaskDao.updateHasAtta(0, taskId);
        // 先去数据库删除该附件的记录
        iTaskAttachedDao.deleteById(attachedId);
        // 判断传输过来的文件是什么类型,从而决定要请求哪个文件服务来删除
        if (fileType == 0)// 如果是图片文件则调用Training-ImageManage-Service
            new ImageInterface(restTemplate).imageDelete(hashOrUuid);
        else
            // 如果是普通文件则调用Training-FileManage-Service
            new FileInterface(restTemplate).fileDelete(hashOrUuid);
    }

    // 调用文件服务获取附件二进制文件
    public byte[] getAttached(String hashOrUuid, int fileType) {
        // 判断传输过来的文件是什么类型,从而决定要请求哪个文件服务来删除
        if (fileType == 0)// 如果是图片文件则调用Training-ImageManage-Service
            return imageInterface.getImage(hashOrUuid);
        else
            // 如果是普通文件则调用Training-FileManage-Service
            return fileInterface.getFile(hashOrUuid);
    }

    // 根据任务Id获取所有附件的信息
    public List<TaskAttached> getAllAttachedByTaskId(String taskId) {
        return iTaskAttachedDao.findByTaskId(taskId);
    }

    // 保存单个附件信息
    @Transactional
    public void addAttached(TaskAttached taskAttached) {
        iTaskAttachedDao.save(taskAttached);
    }

    // 获取任务的所有类型
    public List<TaskType> getAllTaskType() {
        return iTaskTypeDao.findAll();
    }

    // 获取任务的所有优先级
    public List<TaskPriority> getAllTaskPriority() {
        return iTaskPriority.findAll();
    }

    // 获取任务的所有状态
    public List<TaskStatus> getAllTaskStatus() {
        return iTaskStatusDao.findAll();
    }

    // 获取能够派发任务的对象
    public String getReceiver(String access_token) {
        return restTemplate.getForObject(
                "http://training-auth-manage-service/branch/"
                        .concat(access_token), String.class);
    }

    // 获取能够派发任务的对象组
    public String getReceiverGroup(String access_token) {
        return restTemplate.getForObject(
                "http://training-auth-manage-service/branchGroup/"
                        .concat(access_token), String.class);
    }

}
